package com.gitee.wsl.struct.generator

import com.gitee.wsl.text.buffer.storage.getChars
import com.gitee.wsl.text.buffer.storage.getCharsFromLong


/**
 * Non-threadsafe temporal variable name generator
 *
 * @author dennis(killme2008@gmail.com)
 */
class VarNameGenerator(private var number: Long = 0) {
    private val chars: CharArray = CharArray(TEMP_LEN)

    private var count: Int

    /**
     * Generate a temporal variable name.
     *
     * @return
     */
    fun gen(): String {
        var n = number++
        if (n < 0) {
            this.number = 0
            n = number++
        }

        append(n)
        return this.chars.concatToString(0, 0 + this.count)
    }

    init {
        TEMP_VAR_PREFIX.getChars(0, TEMP_VAR_PREFIX.length, this.chars, 0)
        this.count = TEMP_VAR_PREFIX.length
    }

    private fun append(l: Long) {
        val appendedLength = stringSize(l)
        val spaceNeeded = TEMP_VAR_PREFIX.length + appendedLength
        getCharsFromLong(l, spaceNeeded, this.chars)
        this.count = spaceNeeded
    }

    companion object {
        private const val TEMP_VAR_PREFIX = "A_"

        private const val TEMP_LEN = TEMP_VAR_PREFIX.length + Long.MAX_VALUE.toString().length

        // Moved from Long.stringSize
        fun stringSize(x: Long): Int {
            var p: Long = 10
            for (i in 1..18) {
                if (x < p) {
                    return i
                }
                p *= 10
            }
            return 19
        }


        val DigitOnes: CharArray = charArrayOf(
            '0',
            '1',
            '2',
            '3',
            '4',
            '5',
            '6',
            '7',
            '8',
            '9',
            '0',
            '1',
            '2',
            '3',
            '4',
            '5',
            '6',
            '7',
            '8',
            '9',
            '0',
            '1',
            '2',
            '3',
            '4',
            '5',
            '6',
            '7',
            '8',
            '9',
            '0',
            '1',
            '2',
            '3',
            '4',
            '5',
            '6',
            '7',
            '8',
            '9',
            '0',
            '1',
            '2',
            '3',
            '4',
            '5',
            '6',
            '7',
            '8',
            '9',
            '0',
            '1',
            '2',
            '3',
            '4',
            '5',
            '6',
            '7',
            '8',
            '9',
            '0',
            '1',
            '2',
            '3',
            '4',
            '5',
            '6',
            '7',
            '8',
            '9',
            '0',
            '1',
            '2',
            '3',
            '4',
            '5',
            '6',
            '7',
            '8',
            '9',
            '0',
            '1',
            '2',
            '3',
            '4',
            '5',
            '6',
            '7',
            '8',
            '9',
            '0',
            '1',
            '2',
            '3',
            '4',
            '5',
            '6',
            '7',
            '8',
            '9',
        )

        val digits: CharArray = charArrayOf(
            '0',
            '1',
            '2',
            '3',
            '4',
            '5',
            '6',
            '7',
            '8',
            '9',
            'a',
            'b',
            'c',
            'd',
            'e',
            'f',
            'g',
            'h',
            'i',
            'j',
            'k',
            'l',
            'm',
            'n',
            'o',
            'p',
            'q',
            'r',
            's',
            't',
            'u',
            'v',
            'w',
            'x',
            'y',
            'z'
        )

        val DigitTens: CharArray = charArrayOf(
            '0',
            '0',
            '0',
            '0',
            '0',
            '0',
            '0',
            '0',
            '0',
            '0',
            '1',
            '1',
            '1',
            '1',
            '1',
            '1',
            '1',
            '1',
            '1',
            '1',
            '2',
            '2',
            '2',
            '2',
            '2',
            '2',
            '2',
            '2',
            '2',
            '2',
            '3',
            '3',
            '3',
            '3',
            '3',
            '3',
            '3',
            '3',
            '3',
            '3',
            '4',
            '4',
            '4',
            '4',
            '4',
            '4',
            '4',
            '4',
            '4',
            '4',
            '5',
            '5',
            '5',
            '5',
            '5',
            '5',
            '5',
            '5',
            '5',
            '5',
            '6',
            '6',
            '6',
            '6',
            '6',
            '6',
            '6',
            '6',
            '6',
            '6',
            '7',
            '7',
            '7',
            '7',
            '7',
            '7',
            '7',
            '7',
            '7',
            '7',
            '8',
            '8',
            '8',
            '8',
            '8',
            '8',
            '8',
            '8',
            '8',
            '8',
            '9',
            '9',
            '9',
            '9',
            '9',
            '9',
            '9',
            '9',
            '9',
            '9',
        )
    }
}

val Generator.VarName:StringGeneratorWithLength get() = {length-> VarNameGenerator(length.toLong()).gen()}